<template>
  <div class="qm-table-form-modal">
    <!-- 自定义表单 -->
    <template v-if="useFormPage">
      <component
        ref="formPage"
        :is="formPath"
        v-if="formPath"
        v-bind:viewModel="viewModel"
        v-bind="viewModel"
        v-bind:formData="viewModel.mozdels.model"
        v-bind:model="viewModel.models.model"
        v-bind:disabled="formDisabled"
      ></component>
    </template>
    <!-- 表单内头部 -->
    <template v-if="showheader">
      <slot
        v-if="!formModalLoading"
        name="formheader"
        v-bind:viewModel="viewModel"
        v-bind="viewModel"
        v-bind:formData="viewModel.models.model"
        v-bind:model="viewModel.models.model"
        v-bind:disabled="formDisabled"
      ></slot>
    </template>
    <!-- 表单中间内容 -->
    <template v-if="!isCustomForm">
      <el-form
        class="qm-table-form"
        :model="viewModel.models"
        v-bind="finalFormOptions"
        :disabled="formDisabled"
        :rules="rules"
        :ref="formRefs"
      >
        <slot
          name="form"
          v-bind:viewModel="viewModel"
          v-bind="viewModel"
          v-bind:formData="viewModel.models.model"
          v-bind:model="viewModel.models.model"
          v-bind:disabled="formDisabled"
        ></slot>
      </el-form>
    </template>
    <!-- 表单内底部 -->
    <template v-if="showfooter">
      <slot
        v-if="!formModalLoading"
        name="formfooter"
        v-bind:viewModel="viewModel"
        v-bind="viewModel"
        v-bind:formData="viewModel.models.model"
        v-bind:model="viewModel.models.model"
        v-bind:disabled="formDisabled"
      ></slot>
    </template>
    <!-- 底部保存和取消按钮 -->
    <div v-if="showFormFooter" slot="footer" class="qm-table-form-row">
      <slot name="formToolbar">
        <el-row
          v-if="keyProp && ['create', 'edit'].includes(pageAction)"
        >
          <el-button
            type="primary"
            :loading="saveLoading"
            @click="submitForm"
            icon="el-icon-circle-check"
            >保 存
          </el-button>
          <!-- <el-button @click="resetForm" >重 置</el-button> -->
          <el-button
            @click="closeform(formRefs)"
            icon="el-icon-circle-close"
            >取 消</el-button
          >
        </el-row>
      </slot>
    </div>
  </div>
</template>

<script>
import Util from "@/libs/framework/util.js";
import request from "@/utils/request";
import _ from "lodash";
export default {
  props: {
    // 是否显示底部插槽
    showfooter: {
      type: Boolean,
    },
    // 是否显示头部插槽
    showheader: {
      type: Boolean,
    },
    // 是否禁止填写
    formDisabled: {
      type: Boolean,
    },
    // 传递过来的数据
    models: {
      type: Object,
      default: () => {},
    },
    // 新建和编辑需要传递的值
    pageAction: {
      type: String,
      default: "create",
    },
    // 指定的新增页、编辑页和查看页，不指定将统一用 create.vue 来作为表单页
    formPage: {
      type: Object,
      default: () => {
        return {
          // 参考示例
          // create: '/admin/sysUser/create',
          // edit: '/admin/sysUser/create',
          // view: '/admin/sysUser/create'
        };
      },
    },
    // 请求之前，带一个参数：params，仅对于指定urls的实例有效
    beforeQuery: {
      type: Function,
    },
    // 此方法不用了，需要在调用的时候，使用表单的刷新方法
    // 保存后刷新
    refreshAfterSave: {
      type: Boolean,
      default: false,
    },
    // 传递过来的数据
    urls: {
      type: Object,
      default: () => {},
    },
    // 列表刷新类型，取值list、list$1、list$2 等，与controller的this.urls.query的类型对应
    // 值为 none 表示不刷新
    refreshType: {
      type: String,
      default: "list",
    },
    // 接收一个数组参数，表单的ref值数组
    formValidate: {
      type: Function,
    },
    // 主键属性，指该列表对应的实体的主键属性，如：userId，typeId等，请尽量指定主键属性
    // 双主键请用英文逗号分隔，如：userId,profileId
    keyProp: {
      type: String,
    },
    // 是否显示表单的底部按钮
    showFormFooter: {
      type: Boolean,
      default: true,
    },
    // 是否使用指定的页面来作为表单页
    useFormPage: {
      type: Boolean,
      default: false,
    },
    // 列表刷新的方法实现，将会覆盖默认的列表刷新方法，接收一个参数params，一些请求参数
    refreshFunc: {
      type: Function,
    },
    // 请求之后，带两个参数：isSuccess、result，仅对于指定urls的实例有效
    afterQuery: {
      type: Function,
    },
        // 分页行的一些属性配置，请参考vxe-table 3.x版本文档：https://xuliangzhan_admin.gitee.io/vxe-table/#/pager/api
    pagerOptions: {
      type: Object,
      default: () => {}
    },
    // 默认为false，不自定义，使用组件提供的表单，rules属性有效
    isCustomForm: {
      type: Boolean,
    },
      /**
     * 是否启用el-pagination的分页组件，默认true，false 表示使用vxe-pager
     *
     * 注：嵌套的 el-dialog 或 vxe-modal 里面存在 vxe-pager 时，点击分页按钮可能会出现页面跳转(刷新)的问题。
     * 出现此问题，请检查vxe-pager组件是否内嵌于form表单内，如果是，只需要移出form表单即可。
     *
     * 原因：vxe-pager被el-form(form表单)包裹时，点击分页按钮会触发表单的action属性，从而导致页面跳转(刷新)的问题。
     */
    elPager: {
      type: Boolean,
      default: true
    },
    // 表单的ref值，多个用英文逗号分隔，用于表单校验
    formRefs: {
      type: String,
      default: "qmGenForm",
    },
    // 表单的一些属性校验规则，支持一个表单内多个对象的校验，
    // 请参考ElementUI 2.x版本文档：https://element.eleme.cn/#/zh-CN/component/form
    rules: {
      type: Object,
      default: () => {},
    },
    // 表单的一些属性配置，请参考ElementUI 2.x版本文档：https://element.eleme.cn/#/zh-CN/component/form
    formOptions: {
      type: Object,
      default: () => {},
    },
  },
  data() {
    return {
      formModalVisible: false,
      formModalLoading: false,
      formPath: "",
      viewModel: {
        search: {},
        controlData: {},
        models: {
          model: {},
        },
        defaults: {},
        enums: {},
        initMessage: null,
      },
      primaryKey: {},
      saveLoading: false,
      tableLoading: false,
      context: {},
    };
  },
  methods: {
    doValidate(formName) {
      if (this.useFormPage) {
        return this.$refs["formPage"].$refs[formName].validate();
      }
      if (this.isCustomForm) {
        return this.$refs[formName].validate();
      }
      return this.$refs[formName].validate();
    },
    defaultFormValidate(forms, idx, rs, rj) {
      this.doValidate(forms[idx])
        .then((valid) => {
          if (valid) {
            if (forms.length - 1 === idx) {
              rs(true);
            } else {
              this.defaultFormValidate(forms, idx + 1, rs, rj);
            }
          } else {
            rj(false);
          }
        })
        .catch((e) => {
          console.error(e);
          this.notifyError("表单检验不通过，请检查表单");
        });
    },
    validate() {
      let formNames = this.formRefs;
      let forms = formNames.split(",");
      if (this.formValidate) {
        return this.formValidate(forms);
      }
      return new Promise((rs, rj) => {
        this.defaultFormValidate(forms, 0, rs, rj);
      });
    },
    appendPrimaryKey(url) {
      if (!url) {
        return "";
      } else {
        for (let o in this.primaryKey) {
          let v = this.primaryKey[o];
          if (v != undefined) {
            let joinChar = url.indexOf("?") == -1 ? "?" : "&";
            url += joinChar;
            url += o + "=" + (this.primaryKey[o] || "");
          }
        }
        return url;
      }
    },
    // 保存按钮
    submitForm() {
      this.validate()
        .then((valid) => {
          if (valid) {
            let postModel = this.viewModel.models;
            let $formPage = this.$refs["formPage"];
            let url = this.isRemoteList ? this.urls.save : this.urls.save;
            let keyp = _.get(postModel.model,this.keyProp)
            if(this.pageAction === 'edit'){
              url =this.appendPrimaryKey(url) + '?' +this.keyProp+'=' +keyp
            }else{
              url = this.appendPrimaryKey(url);
            }
            // url = this.appendPrimaryKey(url);
            let next = true;
            if (this.useFormPage && $formPage && $formPage.onBeforeSave) {
            let go = $formPage.onBeforeSave(postModel);
              // undefined 是没有写return返回值的情况，可能有人忘记写返回值，这里帮忙处理了
              next = go === true || go === undefined;
            }
            if (!next) {
              return;
            }
            this.saveLoading = true;
            this.save(postModel, url)
              .then((r) => {
                let success = (r || {}).success;
                if (this.useFormPage && $formPage && $formPage.onAfterSave) {
                  $formPage.onAfterSave(success, r);
                }
                if (success) {
                  this.formModalVisible = false;
                  this.saveLoading = false;
                  this.$emit('submitForm')
                  if (this.refreshAfterSave) {
                    this.refresh();
                  }
                } else {
                  this.notifyError((r || {}).message || "操作失败，请稍后再试");
                  this.saveLoading = false;
                }
              })
              .catch(() => {
                this.saveLoading = false;
              });
          } else {
            console.log("error submit!!");
            this.notifyError("表单检验不通过，请检查表单");
            return false;
          }
        })
        .catch((err) => {
          console.error(err);
          this.notifyError("表单检验不通过，请检查表单");
        });


    },
    //#region 保存
    onBeforeSave(postModel) {
      return true;
    },
    // 表单校验方法，如果使用qm-table组件的表单功能，则不需重写此方法
    onValidate() {
      return Promise.resolve();
    },
    save(postModel = this.viewModel.models, url) {
      return new Promise((resolve, reject) => {
        if (!url) {
          url = this.appendPrimaryKey(this.urls.save);
        }
        if (postModel == undefined || url == undefined) {
          this.afterSave(false, {
            message: "PostModel或者URL不可为undefined",
          });
          reject();
        } else {
          postModel = Util.cloneDeep(postModel);
          postModel.pageAction = this.pageAction;
          this.onValidate()
            .then((valid) => {
              let next = this.onBeforeSave(postModel);
              // undefined 是没有写return返回值的情况，可能有人忘记写，这里帮忙处理了
              if (next === true || next === undefined) {
                request({
                  url: url,
                  method: "post",
                  data: postModel,
                })
                  .then((r) => {
                    this.afterSave(r.success, r);
                    resolve(r);
                  })
                  .catch((e) => {
                    this.afterSave(false, e);
                    reject(e);
                  });
              } else {
                reject();
              }
            })
            .catch((e) => {
              this.notifyError("表单校验不通过！");
            });
        }
      });
    },
    afterSave(isSuccess, result) {
      if (
        isSuccess &&
        result.parameters &&
        result.parameters.keys &&
        this.context.pageAction == "create"
      ) {
        this.context.pageAction = "edit";
        this.context.pageActionText = "编辑";
        this.context.primaryKey = result.parameters.keys;
      }

      this.$message({
        showClose: true,
        message:
          result.message || (isSuccess ? "保存成功" : "保存失败，请稍后重试"),
        type: isSuccess ? "success" : "error",
        onClose: ($message) => {
          this.onAfterSave(isSuccess, result);
        },
      });
    },
    onAfterSave(isSuccess, result) {},
    //#endregion
    // 列表刷新
    refresh(params = {}) {
      params = _.extend(
        {},
        {
          start: (this.data.startIndex - 1) * this.data.pageSize,
          length: this.data.pageSize,
        },
        params
      );
      if (this.refreshFunc) {
        return this.refreshFunc(params);
      }
      if (this.isRemoteList) {
        this.fetchListData(params);
      } else {
        // 此方法还未进行处理
        if (this.refreshType && this.refreshType !== "none") {
          this.tableLoading = true;
          this.fetchData(params, this.refreshType, false).then((r) => {
            this.tableLoading = false;
          });
        }
      }
    },
    fetchListData(otherParams = {}) {
      if (!this.isRemoteList) {
        return;
      }
      let url = this.urls.query;
      url = _.isString(url)
        ? { url: url, method: "post" }
        : _.extend({ url: "", method: "post" }, url);
      let params = _.extend(
        {},
        {
          start: 0,
          length: this.finalPagerOptions.pageSize || 10,
          draw: 1,
          query: {},
        },
        otherParams
      );
      if (this.beforeQuery) {
        this.beforeQuery(params);
      }
      let queryData =
        url.method.toLowerCase() === "get"
          ? { params: params }
          : { data: params };
      this.tableLoading = true;
      request({
        url: url.url,
        method: url.method,
        ...queryData,
      })
        .then(
          (result) => {
            if (this.afterQuery) {
              this.afterQuery(true, result);
            }
            this.data = _.extend(this.data, result);
            this.tableLoading = false;
          },
          (result) => {
            if (this.afterQuery) {
              this.afterQuery(false, result);
            }
            this.tableLoading = false;
            this.msgError("获取列表数据失败，请稍后重试");
          }
        )
        .catch((err) => {
          console.error(err);
          this.tableLoading = false;
        });
    },
    onBeforeGetEntity(params) {},
    onAfterGetEntity(result) {},
    /**
     * 获取实体数据，如果参数没有指定实体的主键属性和值，则返回一个空的实体
     * @param {*} params 参数
     * @param {*} url 请求的url
     */
    getEntity(
      params = {
        pageAction: "create",
      },
      url = this.urls.entity
    ) {
      return new Promise((resolve, reject) => {
        if (!url) {
          this.msgError("没有指定获取实体的url");
          reject("没有指定获取实体的url");
        }
        this.onBeforeGetEntity(params);
        request({
          url: url,
          method: "post",
          data: params,
        })
          .then((r) => {
            this.onAfterGetEntity(r);
            if (r && !r.initMessage) {
              resolve(r);
            } else {
              reject(r.initMessage || "请求数据失败");
            }
          })
          .catch((e) => {
            reject(e);
          });
      });
    },
    /**
     * 使用指定type的loader请求数据
     * @param {*} params 参数，需指定key和value
     * @param {*} type loader的类型
     */
    fetchData(params, type, preloader = true) {
      let loading;
      if (preloader) {
        loading = this.vm.appLoading("数据加载中...");
      }
      return new Promise((rs, rj) => {
        this.getLoader(type)
          .query(params)
          .then(
            (values) => {
              this.bind(values);
              if (preloader) {
                loading.close();
              }
              rs();
            },
            (values) => {
              if (preloader) {
                loading.close();
              }
              this.vm.msgError("请求失败，请稍候再试");
              console.error(values);
              rs();
            }
          );
      });
    },
    closeform(formRefs){
      this.$refs[formRefs].clearValidate()
      this.$emit('closeform')
    },
    gitmodels(){
        return   this.viewModel.models.model = this.models;
    }
  },
  computed: {
    isRemoteList() {
      // isEmpty用来判定是否为一个空对象，集合，映射或set如果是空返回true，否则false
      // getParent()方法 就 等于this.pageVue     this.pageVue 是inject 传递过来的值
      return !(_.isEmpty(this.urls) || _.isEmpty(this.urls.query));
    },
    finalFormOptions() {
      return _.extend(
        {
          labelWidth: "100px",
        },
        this.formOptions
      );
    },
    finalPagerOptions() {
      if (this.elPager) {
        return _.extend(
          {
            layout: "total, sizes, prev, pager, next, jumper",
            pageSizes: [5, 10, 20, 50, 100]
          },
          this.pagerOptions
        );
      }
      return _.extend(
        {
          layouts: [
            "Total",
            "Sizes",
            "PrevJump",
            "PrevPage",
            "JumpNumber",
            "NextPage",
            "NextJump",
            "FullJump"
          ],
          pageSizes: [5, 10, 20, 50, 100]
        },
        this.pagerOptions
      );
    },
  },
  created(){
    this.gitmodels()
  },
  watch:{
    models(){
      this.gitmodels()
    }
  }
};
</script>

<style scoped lang="scss">
.qm-table-form-modal {
  .qm-table-form {
    max-height: calc(100vh - 200px);
    margin: 8px 16px 8px 8px;
  }
  .qm-table-form-row {
    text-align: right;
    // margin: 12px 0;
  }
}
::v-deep .el-form .el-form-item--small .el-form-item__error {
    margin-top: 0.168958vw;
}
</style>
